<?php

namespace App\Models\Logger;

use App\Http\Requests\Admin\Panx\OperateLog\OperateLogIndexRequest;
use App\Models\Concerns\ScopeFilterable;
use App\Models\Customer\Customer;
use App\Models\Store\Store;
use App\Services\Utils\Agent;
use App\Services\Utils\IpUtils;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * @property int operatorable_id
 * @property int logable_id
 * @property int log_type_id
 * @property null|string operate_staff
 * @property null|string log_staff
 * @property mixed|null log_type
 * @property array|null json_data
 *
 * @method static self filterOperatorableType(string $operatorable_type)
 * @method static self filterLogTypeId(int $log_type_id)
 * @method static self filterOperatorableId(int $operatorable_id)
 * @method static self filterCustomerId(int $customer_id)
 * @method static self filterStoreId(int $store_id)
 * @method self filterContentLog(string $log)
 * @method self filterLogType(int $log_type_id)
 * @method self filterOperateStaff(int $operator_id)
 * @method self filterLogStaff(int $logable_staff_id)
 * @mixin Builder
 */
class OperateLog extends Model
{
    use ScopeFilterable;

    protected $table = 'operate_logs';

    protected $guarded = [];

    protected $casts = [
        'operatorable_id' => 'int',
        'logable_id'      => 'int',
        'log_type_id'     => 'int',
        'json_data'       => 'json',
        'agent_info'      => 'json',
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function operatorable()
    {
        return $this->morphTo();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function logable()
    {
        return $this->morphTo();
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function customer()
    {
        return $this->belongsTo(Customer::class, 'customer_id', 'id');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function store()
    {
        return $this->belongsTo(Store::class, 'store_id', 'id');
    }

    /**
     * @used-by filterOperatorableType()
     * 根据员工类型，查询日志
     * @param Builder $query
     * @param $value
     * @return Builder
     */
    public function scopeFilterOperatorableType(Builder $query, $value)
    {
        if (! $value) return $query;

        return $query->where('operatorable_type', $value);
    }

    /**
     * @used-by filterLogTypeId()
     * 查询记录的类型
     * @param Builder $query
     * @param $value
     * @return Builder
     */
    public function scopeFilterLogTypeId(Builder $query, $value)
    {
        if (! $value) return $query;

        return $query->where('log_type_id', $value);
    }

    /**
     * @used-by filterOperatorableId()
     * 查询执行者
     * @param Builder $query
     * @param $value
     * @return Builder
     */
    public function scopeFilterOperatorableId(Builder $query, $value)
    {
        if (! $value) return $query;

        return $query->where('operatorable_id', $value);
    }

    /**
     * @used-by filterCustomerId()
     * @param Builder $query
     * @param $customer_id
     * @return Builder
     */
    public function scopeFilterCustomerId(Builder $query, $customer_id)
    {
        if (! $customer_id) return $query;

        return $query->where('customer_id', $customer_id);
    }

    /**
     * @used-by filterStoreId()
     * @param Builder $query
     * @param $store_id
     * @return Builder
     */
    public function scopeFilterStoreId(Builder $query, $store_id)
    {
        if (! $store_id) return $query;

        return $query->where('store_id', $store_id);
    }

    /**
     * @param OperateLogIndexRequest $request
     * @return LengthAwarePaginator
     */
    public static function getOperatorLogs(OperateLogIndexRequest $request)
    {
        /** @var LengthAwarePaginator $operate_logs */
        $operate_logs = (new self)
            ->filterTimeRange($request->time_range)
            ->filterLogTypeId($request->log_type_id)
            ->filterOperatorableId($request->operatorable_id)
            ->filterOperatorableType($request->operatorable_type)
            ->filterCustomerId($request->customer_id)
            ->filterStoreId($request->store_id)
            ->with('operatorable', 'customer', 'store')
            ->OrderByDefaultLatest($request->order_column, $request->sort)
            ->paginate($request->per_page?:20);

        $operate_logs->transform(function(OperateLog $operate_log) {
            $operate_log->operate_staff = $operate_log->operatorable->account ?? null;

            $operate_log->addHidden('operatorable');

            return $operate_log;
        });

        return $operate_logs;
    }

    /**
     * @param Model $operator
     * @param Model $log_model
     * @param int $log_type_id
     * @param string $log
     * @param $customer_id
     * @param $store_id
     * @param null $remark
     * @param array $data
     * @param null $ip
     * @return Builder|self
     */
    public static function createLog(Model $operator, Model $log_model,
                                     $log_type_id ,$log, $customer_id, $store_id,
                                     $remark = null, $data = [], $ip = null)
    {
        return (new self)->create([
            "operatorable_id"   => $operator->id,
            "operatorable_type" => class_basename($operator),
            "logable_id"        => $log_model->id,
            "logable_type"      => class_basename($log_model),
            "log"               => $log,
            "log_type_id"       => $log_type_id,
            "remark"            => $remark,
            "json_data"         => $data,
            "ip"                => $ip ?: (new IpUtils)->getIp(),
            'customer_id'       => $customer_id ?? 0,
            'store_id'          => $store_id ?? 0,
            'agent_info'        => (new Agent)->agentInfo(),
        ]);
    }
}
